package io.github.veigara.tcp.framework.protocol;

import io.github.veigara.tcp.framework.event.DeviceEvent;
import io.github.veigara.tcp.framework.event.DeviceEventBus;
import io.github.veigara.tcp.framework.event.DeviceEventType;
import io.github.veigara.tcp.framework.factory.DeviceComponentFactory;
import io.github.veigara.tcp.framework.factory.DeviceComponentFactoryRegistry;
import io.github.veigara.tcp.framework.model.DeviceConnection;
import io.github.veigara.tcp.framework.model.DeviceConnectionInfo;
import io.github.veigara.tcp.framework.DeviceServer;
import io.github.veigara.tcp.framework.model.DeviceType;
import io.github.veigara.tcp.framework.metrics.DeviceMetricsCollector;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.UUID;

/**
 * 设备通道处理器
 */
public class DeviceChannelHandler extends ChannelInboundHandlerAdapter {
    private static final Logger logger = LoggerFactory.getLogger(DeviceChannelHandler.class);

    private final DeviceType deviceType;
    private final DeviceComponentFactoryRegistry factoryRegistry;
    private final DeviceServer deviceServer;
    private final DeviceEventBus eventBus;
    private final DeviceMetricsCollector metricsCollector;

    private DeviceConnection deviceConnection;

    public DeviceChannelHandler(
            DeviceType deviceType,
            DeviceComponentFactoryRegistry factoryRegistry,
            DeviceServer deviceServer,
            DeviceEventBus eventBus,
            DeviceMetricsCollector metricsCollector) {
        this.deviceType = deviceType;
        this.factoryRegistry = factoryRegistry;
        this.deviceServer = deviceServer;
        this.eventBus = eventBus;
        this.metricsCollector = metricsCollector;
    }

    @Override
    public void channelActive(ChannelHandlerContext ctx) {
        String deviceId = UUID.randomUUID().toString();

        DeviceComponentFactory factory = factoryRegistry.getFactory(deviceType);
        ProtocolHandler protocolHandler = factory.createProtocolHandler(null);

        deviceConnection = new DeviceConnection(
                new DeviceConnectionInfo(deviceId),
                ctx.channel(),
                deviceType,
                protocolHandler,
                deviceServer
        );

        protocolHandler.setDeviceConnection(deviceConnection);
        deviceServer.addDeviceConnection(deviceConnection);

        eventBus.publishEvent(new DeviceEvent(
                deviceId,
                DeviceEventType.CONNECTED,
                deviceType
        ));

        logger.info("Device connected: {}, type: {}", deviceId, deviceType);
    }

    @Override
    public void channelInactive(ChannelHandlerContext ctx) {
        if (deviceConnection != null) {
            String deviceId = deviceConnection.getDeviceConnectionInfo().getDeviceId();

            eventBus.publishEvent(new DeviceEvent(
                    deviceId,
                    DeviceEventType.DISCONNECTED,
                    deviceType
            ));

            logger.info("Device disconnected: {}, type: {}", deviceId, deviceType);

            deviceConnection.disconnect();
            deviceConnection = null;
        }
    }

    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) {
        if (deviceConnection != null && deviceConnection.getProtocolHandler() != null) {
            metricsCollector.recordMessageReceived(deviceType);
            deviceConnection.getProtocolHandler().handleMessage(msg);
        } else {
            logger.warn("No device connection or protocol handler available");
            ctx.close();
        }
    }

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
        logger.error("Exception in device channel handler", cause);
        ctx.close();
    }
}